//
//  Property.h
//  面试题
//
//  Created by Toj on 8/9/21.
//

https://juejin.cn/post/6970255715462021157
https://www.jianshu.com/p/baf7f28bfac2
https://www.bilibili.com/video/BV1xK411G7t1/?spm_id_from=333.999.0.0&vd_source=3e10f075fdc52c5ea349eb2abf60adb1

#pragma mark - 问题
1. @property   干什么用的
2. @synthesize 干什么用的
3. @dynamic    干什么用的
4. @property 有哪些修饰关键字

#pragma mark - 1. @property 干什么用的
 iOS 6 之后 LLVM 编译器引入property autosynthesis
@property (修饰关键字) 类型 属性名;

// 可以理解为
@property = ivar + getter + setter
即: 成员变量 + setter方法 + getter方法


#pragma mark - 2. @synthesize 干什么用的
2.1 创建成员变量起一个别名, 不用系统生成的_name,
如果成员变量名已经声明, 就不会在创建新的成员变量
*** 就是类似于绑定同名成员变量

@interface House() { int that; } @end

@implementation House
@synthesize age = that;
- (void)setAge:(int)age { that = age; }
- (int)age { return that; }
@end

2.1.1. 生成一个与属性同名的变量 都叫age
@synthesize age;
有个弊端就是你在重写setter方法的时候 不能这么用, 会造成死循环
只有getter方法可以这么写, 但是不建议

2.1.2. 成员变量起个别名
e.g. 为age起一个别名that
@property (assign, nonatomic) int age;
@synthesize age = that;
- (void)setAge:(int)age { that = age; }
- (int)age { return that; }

2.2. 生成setter/ getter方法
利用clang:
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 文件名
就可以看到


#pragma mark - 3. @dynamic 干什么用的
如果父类有属性name, 子类也有属性name, 那么系统会报警告, 由父类实现
系统会报如下警告:
Auto property synthesis will not synthesize property 'name'; it will be implemented by its superclass, use @dynamic to acknowledge intention
大致意思:
自动属性合成将不会合成属性'name';它将由它的超类实现，使用@dynamic来确认意图
简单点就是告诉编辑器 属性由此类实现

#pragma mark - 4. @property 有哪些修饰关键字
@property (strong, nonatomic, setter=nm:, getter=isName, nullable, readwrite) NSString *name;
4.1.1: 原子/ 非原子
 (atomic, nonatomic)
4.1.2. setter/ getter方法名
 (setter=name:, getter=isReadOnly)
4.1.3. 读写
 (readonly, readwrite)
4.1.4. 修饰引用属性的可Null, 必须是引用类型
 (nonnull, nullable, null_resettable, null_unspecified)
4.1.5. 修饰属性的引用类型
 (strong, weak, copy, unsafe_unretained, assign, retain)

4.2. 每个都是什么意思?

4.2.1 原子/ 非原子
4.2.1.1 atomic: 原子, 多线程安全(话面意思, 其实也是不安全的),
因为线程安全所以使用效率低, getter/ setter里面有锁.
不安全的例子:
1. e.g. 数组多个线程同时访问 不安全,
2. e.g. 一个属性即读又写    不安全
4.2.1.2 nonatomic: 非原子, 使用率高, 但是不安全,
怎么都不安全, 建议使用 非原子

4.2.2 setter/ getter方法 重命名而已

4.2.3 readonly/ readwrite 属性的读写操作

4.2.4 属性默认是否null
nonnull: 不能为空
nullable: 可以为空
null_resetable: getter不能为空, 但是setter可以为空, 所以必须重写处理返回null值
null_unspecified: 不确定因素

4.2.5. 修饰属性的引用类型
assign: 既能修饰对象, 也能修饰基本数据类型,
如果修饰对象不会对引用计数+1, 最后对象释放不会被设置nil
